package com.google.code.bigyang.nio;

import java.io.IOException;
import java.net.Socket;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.google.code.bigyang.base.QueueThreadPool;
import com.google.code.bigyang.base.Task;

public class NioSocketPoller extends NioPoller implements Runnable {

	private ConcurrentLinkedQueue<Socket> queue = new ConcurrentLinkedQueue<Socket>();
	
	private Selector selector;
	
	
	private QueueThreadPool pool = new QueueThreadPool();
	
	public void config() throws IOException {
		selector = Selector.open();
		new Thread(pool,"pool").start();
		
	}
	
	public void service() {
		run();
	}
	
	public void run() {
		while(true) {
			try {
				Socket socket = queue.poll();
				if(socket != null) {
					NioSession session = createSession(socket);
					socket.getChannel().register(selector, SelectionKey.OP_READ, session);
					
				}
				
				int count = selector.select(5 * 1000);
				if(count == 0) {
					continue;
				}
				
				Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
				while(iter.hasNext()) {
					SelectionKey key = iter.next();
					if(key.isReadable()) {
						NioSocketSession session = (NioSocketSession)key.attachment();
						Task task = new Task(session);
						pool.schedule(task);
					} else if(key.isWritable()) {
						
					} else if(key.isConnectable()) {
						
					}
				}
				
				
			} catch (ClosedChannelException e) {
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	
	public void addToQueue(Socket socket) {
		queue.add(socket);
	}
	
	
	private NioSocketSession createSession(Socket socket) throws IOException {
		SocketChannel channel = socket.getChannel();
		channel.configureBlocking(false);
		NioSocketSession session = new NioSocketSession();
		session.setChannel(channel);
		return session;
	}
}
